<template>
  <view
    class="tn-tabs"
    :class="[tabsClass]"
    :style="tabsStyle"
    :id="tabsId"
  >
    <scroll-view
      class="tn-tabs__scroll-view"
      :scroll-x="scroll"
      scroll-with-animation
      :scroll-left="scrollLeft"
    >
      <view class="tn-tabs__wrap">
        <!-- tab-item -->
        <view
          v-for="(item, index) in data"
          :key="index"
          :id="`tn-tabs__item-${index}`"
          class="tn-tabs__item"
          :class="[itemClass(index)]"
          :style="itemStyle(index)"
          @tap.stop="itemClick(index)"
        >
          <!-- 内容 -->
          <view class="tn-tabs__content">
            {{ item.title }}
            <tn-badge
              v-if="item.badge"
              size="sm"
              :bg-color="item?.badgeBgColor || 'tn-bg-red'"
              :dot="item?.dotBadge || false"
              absolute
              absolute-center
            >{{ item?.badgeContent || '' }}</tn-badge>
          </view>
          <!-- bar -->
          <view v-if="bar" class="tn-tabs__bar" :class="[barClass(index)]" :style="barStyle"></view>
        </view>
      </view>
    </scroll-view>
  </view>
</template>

<script lang="ts" setup>
import { tabsProps, tabsEmits, TabData } from '../../../types/tn-tabs'
import { ColorInfo } from '../../../types/tuniao-ui'
import { computed, watchEffect, ref, watch, nextTick, 
  getCurrentInstance, ComponentInternalInstance,
  onMounted, CSSProperties } from 'vue'
import useComponentColor from '../../../libs/hooks/useComponentColor'
import { handleValueWithUnit, uuid, getRectInfo } from '../../../utils'
import TnBadge from '../../tn-badge/src/Badge.vue'


const props = defineProps(tabsProps)
const emits = defineEmits(tabsEmits)

const { generateColorInfo, splitColorInfo } = useComponentColor()
let componentColorInfo = generateColorInfo(props?.color || '', props?.bgColor || '')
// 监听颜色变化实时修改颜色对应的属性
watchEffect(() => {
  componentColorInfo = generateColorInfo(props?.color || '', props?.bgColor || '')
})

// 解析激活时item颜色
const activeColor = computed<ColorInfo>(() => {
  return splitColorInfo('color', props?.activeColor || '')
})
// 解析滑块颜色
const barColor = computed<ColorInfo>(() => {
  return splitColorInfo('bg', props?.barColor || '')
})
// 解析阴影颜色
const shadowColor = computed<ColorInfo>(() => {
  return splitColorInfo('shadow', props?.shadowColor || '')
})

// tabsItem数据
const data = computed<TabData[]>(() => {
  if (props?.data?.length > 0) {
    return props.data as TabData[]
  }
  return []
})
// 当前激活的索引
let currentIndex = ref<number>(0)
watch(data, (nVal: TabData[], oVal: TabData[]) => {
  // 如果数据发生变化则重新计算相关属性
  if (nVal.length !== oVal.length) currentIndex.value = 0
  nextTick(() => {
    initTabsRect()
  })
})

watch(() => props.current, (nVal: string | number) => {
  nextTick(() => {
    if (nVal === 'undefined') return
    // 更新激活索引并更新tabs滑动位置
    currentIndex.value = Number(nVal)
    scrollToCenter()
  })
},{
  immediate: true
})

// tabs样式
const tabsStyle = computed<CSSProperties>(() => {
  let style: CSSProperties = {}
  if (props?.height) {
    style.height = handleValueWithUnit(props.height)
  }
  if (props?.fontSize) {
    style.fontSize = handleValueWithUnit(props.fontSize)
  }
  if (componentColorInfo.style?.color) {
    style.color = componentColorInfo.style.color
  }
  if (componentColorInfo.style?.backgroundColor) {
    style.backgroundColor = componentColorInfo.style.backgroundColor
  }
  if (props?.shadow && shadowColor.value.type === 'style') {
    style.boxShadow = `6rpx 6rpx 8rpx ${shadowColor.value.value}`
  }

  // 距离顶部的偏移高度
  if (props?.top) {
    style.marginTop = handleValueWithUnit(props.top)
  }

  return Object.assign(style, props?.customStyle || {})
})
// item样式
const itemStyle = computed<(index: number) => CSSProperties>(() => {
  return (index: number) => {
    let style: CSSProperties = {}
    
    if (props.duration !== 'undefined') {
      style.transitionDuration = Number(props.duration) / 1000 + 's'
    }

    if (index === currentIndex.value) {
      if (activeColor.value.type === 'style') {
        style.color = activeColor.value.value
      }
      return Object.assign(style, props?.activeItemStyle || {})
    }

    return Object.assign(style, props?.itemStyle || {})
  }
})
// 底部滑块样式
const barStyle = computed<CSSProperties>(() => {
  let style: CSSProperties = {}
  if (props.duration !== 'undefined') {
    style.transitionDuration = Number(props.duration) / 1000 + 's'
  }
  if (barColor.value.type === 'style') {
    style.backgroundColor = barColor.value.value
  }
  return Object.assign(style, props?.barStyle || {})
})

// tabs对应的类
const tabsClass = computed<string>(() => {
  let clazz: string[] = []
  if (componentColorInfo.class.length > 0) {
    clazz.push(...componentColorInfo.class)
  }
  // 设置默认type
  if (props?.type) {
    clazz.push(`tn-type-${props.type}--light`)
  }
  // 设置阴影
  if (props?.shadow) {
    clazz.push('tn-shadow')
    if (shadowColor.value.type === 'class') {
      clazz.push(shadowColor.value.value)
    }
  }

  return clazz.join(' ')
})
// item对应的类
const itemClass = computed<(index: number) => string>(() => {
  return (index: number) => {
    let clazz: string[] = []
    if (index === currentIndex.value) {
      if (activeColor.value.type === 'class') {
        clazz.push(activeColor.value.value)
      }
      clazz.push('tn-tabs__item--active')
    }
    if (props?.scroll) {
      clazz.push('tn-tabs__item--scroll')
    }

    return clazz.join(' ')
  }
})
// 底部滑块对应样式
const barClass = computed<(index: number) => string>(() => {
  return (index: number) => {
    let clazz: string[] = []
    if (index === currentIndex.value) {
      clazz.push('tn-tabs__bar--active')
    }
    if (barColor.value.type === 'class') {
      clazz.push(barColor.value.value)
    }

    return clazz.join(' ')
  }
})


// 组件对象
const instance: ComponentInternalInstance = getCurrentInstance() as ComponentInternalInstance
// tabs唯一标识
let tabsId: string = uuid()
// tabs组件节点信息
let tabsLeft: number = 0
let tabsWidth: number = 0
// 初始化tabs相关信息
const initTabsRect = async () => {
  try {
    const rectInfo = await getRectInfo(`#${tabsId}`, instance)
    if (!rectInfo) {
      setTimeout(() => {
        initTabsRect()
      }, 50);
      return
    }

    tabsLeft = rectInfo.left || 0
    tabsWidth = rectInfo.width || 0

    // 获取tabItem节点信息
    initTabsItemRect()
  } catch (e) {
    console.log('[tn-tabs]获取tabs节点信息失败');
  }
}

// tabItemRect类型
type TabItemRectInfo = {
  left: number,
  width: number
}
// 初始化tabItem相关信息
let tabItemRectInfos: TabItemRectInfo[] = []
const initTabsItemRect = () => {
  const query = uni.createSelectorQuery().in(instance)
  // 添加筛选标识
  for (let i = 0; i < data.value.length; i++) {
    query.select(`#tn-tabs__item-${i}`).boundingClientRect(() => {})
  }
  query.exec((res: UniApp.NodeInfo[]) => {
    tabItemRectInfos = []
    for (let i = 0; i < res.length; i++) {
      tabItemRectInfos.push({
        left: res[i].left || 0,
        width: res[i].width || 0
      })
    }
  })
}

// scroll-view滚动距离
let scrollLeft = ref<number>(0)
// 滚动scrollView保持活动的标签在屏幕中间
const scrollToCenter = () => {
  // 如果tabs不允许滚动则直接退出不进行操作
  if (!props?.scroll) return

  // 获取当前选中的item节点信息
  const itemRectInfo: TabItemRectInfo = tabItemRectInfos[currentIndex.value]
  if (!itemRectInfo) return

  // 选中item的左边到tabs左边的距离
  const offsetLeft = itemRectInfo.left - tabsLeft
  // 设置scrollView滚动距离
  const scrollLeftValue = offsetLeft - ((tabsWidth - itemRectInfo.width) / 2)
  scrollLeft.value = scrollLeftValue < 0 ? 0 : scrollLeftValue
}

// 加载完毕后执行
onMounted(() => {
  nextTick(() => {
    setTimeout(() => {
      initTabsRect()
    }, 50);
  })
})

// item点击事件
const itemClick = (index: number) => {
  if (index === currentIndex.value) return
  currentIndex.value = index
  scrollToCenter()
  emits('change', index)
}

</script>

<script lang="ts">
export default {
  options: {
    // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现(不会出现shadow节点下再去创建元素)
    virtualHost: true
  }
}
</script>

<style lang="scss" scoped>
@import '../../../theme.scss';

.tn-tabs {
  position: relative;
  width: 100%;
  background-color: #FFFFFF;

  &__scroll-view {
    position: relative;
    width: 100%;
    height: 100%;
    white-space: nowrap;
  }

  &__wrap {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: flex-start;
  }

  &__item {
    flex: 1;
    height: 100%;
    padding: 0 20rpx;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    transition-property: all;

    &--scroll {
      flex: auto;
    }

    &--active {
      font-weight: 500;
    }
  }

  &__content {
    position: relative;
  }

  &__bar {
    position: absolute;
    bottom: 0;
    left: 50%;
    height: 6rpx;
    width: 40%;
    transform: translateX(-50%) scaleX(0);
    background-color: $tn-main-color;
    border-radius: 10rpx;
    transform-origin: 0% 0%;

    &--active {
      transform: translateX(-50%) scaleX(1);
    }
  }
}

/* 内置类型颜色 start */
@for $i from 1 to length($tn-type-names)+1 {
  $typeName: nth($tn-type-names, $i);
  .tn-type-#{$typeName}--light .tn-tabs__bar {
    background-color: map-get(map-get($tn-type-color-map, $typeName), "normal") !important;
  }
}
/* 内置类型颜色 end */
</style>
